package com.jfirer.mvc.viewrender.impl;

import com.jfirer.baseutil.bytecode.support.AnnotationContextFactory;
import com.jfirer.baseutil.reflect.ReflectUtil;
import com.jfirer.jfire.core.ApplicationContext;
import com.jfirer.jfire.core.inject.notated.PropertyRead;
import com.jfirer.jfire.core.prepare.ContextPrepare;
import com.jfirer.jfire.core.prepare.annotation.Import;
import com.jfirer.jfire.util.PrepareConstant;
import com.jfirer.mvc.core.ModelAndView;
import com.jfirer.mvc.viewrender.DefaultResultType;
import com.jfirer.mvc.viewrender.ViewRender;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.ResourceLoader;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.beetl.core.resource.WebAppResourceLoader;
import org.beetl.ext.web.SessionWrapper;
import org.beetl.ext.web.WebVariable;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

public class BeetlRender implements ViewRender
{
    @Import(BeetlRenderImporter.class)
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface EnableBeetlRender
    {
        /**
         * 渲染器的模式。<br/>
         * 如果是webapp目录下，模式为webapp:${path},其中${path}代表模板路径。如果是根路径，则直接为webapp<br/>
         * 如果是在类路径下，模式为classpath:${path},其中${path}代表目录路径
         *
         * @return
         */
        public String value();
    }

    public static class BeetlRenderImporter implements ContextPrepare
    {

        @Override
        public ApplicationContext.NeedRefresh prepare(ApplicationContext context)
        {
            AnnotationContextFactory annotationContextFactory = context.getAnnotationContextFactory();
            for (Class<?> each : context.getConfigurationClassSet())
            {
                if (annotationContextFactory.get(each).isAnnotationPresent(EnableBeetlRender.class))
                {
                    EnableBeetlRender beetlRender = annotationContextFactory.get(each).getAnnotation(EnableBeetlRender.class);
                    context.getEnv().putProperty("jfire.mvc.mode", beetlRender.value());
                }
            }
            return ApplicationContext.NeedRefresh.NO;
        }

        @Override
        public int order()
        {
            return PrepareConstant.DEFAULT_ORDER;
        }
    }

    private GroupTemplate  gt   = null;
    @Resource
    private ServletContext servletContext;
    /**
     * 渲染器的模式。<br/>
     * 如果是webapp目录下，模式为webapp:${path},其中${path}代表模板路径。如果是根路径，则直接为webapp<br/>
     * 如果是在类路径下，模式为classpath:${path},其中${path}代表目录路径
     */
    @PropertyRead("jfire.mvc.mode")
    private String         mode = "webapp";

    @PostConstruct
    public void init()
    {
        ResourceLoader loader = null;
        if (mode.startsWith("webapp"))
        {
            if ("webapp".equals(mode))
            {
                loader = new WebAppResourceLoader(servletContext.getRealPath(""));
            }
            else
            {
                loader = new WebAppResourceLoader(servletContext.getRealPath(mode.substring(6)));
            }
        }
        else
        {
            loader = new ClasspathResourceLoader(mode.substring(10));
        }
        try
        {
            Configuration configuration = Configuration.defaultConfiguration();
            gt = new GroupTemplate(loader, configuration);
            gt.getConf().setDirectByteOutput(true);
        }
        catch (Exception e)
        {
            ReflectUtil.throwException(e);
        }
    }

    @Override
    public void render(HttpServletRequest request, HttpServletResponse response, Object result) throws Throwable
    {
        ModelAndView vm          = (ModelAndView) result;
        WebVariable  webVariable = new WebVariable();
        webVariable.setRequest(request);
        webVariable.setResponse(response);
        vm.addObject("session", new SessionWrapper(request, request.getSession(false)));
        vm.addObject("servlet", webVariable);
        vm.addObject("request", request);
        vm.addObject("ctxPath", request.getContextPath());
        render(vm, request.getServletContext(), response.getOutputStream());
        response.getOutputStream().flush();
    }

    public void render(ModelAndView vm, ServletContext servletContext, OutputStream outputStream)
    {
        String              ajaxId   = null;
        String              key      = vm.getModelName();
        Map<String, Object> data     = vm.getData();
        Template            template = null;
        try
        {
            int ajaxIdIndex = key.lastIndexOf("#");
            if (ajaxIdIndex != -1)
            {
                ajaxId = key.substring(ajaxIdIndex + 1);
                key = key.substring(0, ajaxIdIndex);
                template = gt.getAjaxTemplate(key, ajaxId);
            }
            else
            {
                template = gt.getTemplate(key);
            }
            WebVariable webVariable = new WebVariable();
            template.binding(data);
            template.binding("servlet", webVariable);
            template.binding("ctxPath", servletContext.getContextPath());
            template.renderTo(outputStream);
            outputStream.flush();
        }
        catch (Exception e)
        {
            ReflectUtil.throwException(e);
        }
    }

    /**
     * 可以添加更多的绑定
     *
     * @param template 模板
     * @param key      模板的资源id
     * @param request
     * @param response
     * @param args     调用render的时候传的参数
     */
    protected void modifyTemplate(Template template, String key, HttpServletRequest request, HttpServletResponse response, Object... args)
    {
    }

    @Override
    public String renderType()
    {
        return DefaultResultType.Beetl;
    }
}
